﻿#pragma once

#include "../common/BasePclProvider.h"
#include "./EstimatingSurfaceNormalsModel.h"
#include "pcl/includePcl.h"

/// <summary>
/// EstimatingSurfaceNormalsProvider
/// </summary>
class EstimatingSurfaceNormalsProvider : public BasePclProvider
{
    Q_OBJECT

public:
    EstimatingSurfaceNormalsProvider();

public:
    void initEditor(QtTreePropertyBrowser* editor);
    void valueChanged(QtProperty*, double) override;
    void valueChanged(QtProperty*, QString) override;
    void valueChanged(QtProperty*, int) override;
    void valueChanged(QtProperty*, bool) override;
    void valueChanged(QtProperty*, const QColor&) override;
    void close() override;
    void doLoadPcd();
    void doAction();

private:
    /**
     * @brief Estimating Surface Normals in a PointCloud
     * https://pcl.readthedocs.io/projects/tutorials/en/master/normal_estimation.html
     * data: ???
     * @param cloud
     * @param model
     * @return
     */
    template <typename PointT>
    void impl(shared_ptr<pcl::PointCloud<PointT>> cloud, EstimatingSurfaceNormalsModel& model)
    {
        // Create the normal estimation class, and pass the input
        // dataset to it
        pcl::NormalEstimation<PointT, pcl::Normal> ne;
        ne.setInputCloud(cloud);

        // Create an empty kdtree representation, and pass it to the normal
        // estimation object. Its content will be filled inside the object,
        // based on the given input dataset (as no other search surface is
        // given).
        shared_ptr<pcl::search::KdTree<PointT>> tree(new pcl::search::KdTree<PointT>());
        ne.setSearchMethod(tree);

        // Output datasets
        pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);

        // Use all neighbors in a sphere of radius 3cm
        ne.setRadiusSearch(model.radiusSearch());

        // Compute the features
        ne.compute(*normals);

        // cloud_normals->size () should have the same size as the input
        // cloud->size ()*
        PclContext::get().viewer()->removePointCloud("normals");
        PclContext::get().viewer()->addPointCloudNormals<PointT, pcl::Normal>(
            cloud, normals, model.level(), model.scale(), "normals"
        );
        PclContext::get().updateUI();
    }
};
